﻿using Basic.FlowApplication.Extend;
using Basic.FlowApplication.Interface;
using Basic.FlowApplication.Linq;
using Basic.FlowApplication.Model;
using Basic.FlowApplication.Model.AuditLog;
using Basic.FlowExtendService;
using Basic.FlowRemoteModel;
using Basic.FlowRemoteModel.Application.Model;
using Basic.FormRemoteModel;
using Basic.FormRemoteModel.QueryInter.Model;
using Basic.HrRemoteModel.Emp.Model;
using WeDonekRpc.Client.Attr;
using WeDonekRpc.Helper;

namespace Basic.FlowApplication.AuditEvent
{
    /// <summary>
    /// 节点审批通过
    /// </summary>
    [IocName("Audit_0")]
    [ClassLifetimeAttr(ClassLifetimeType.SingleInstance)]
    internal class AuditPassEvent : IItemAuditEvent
    {
        private readonly IEmpService _Emp;
        private readonly IFormInterService _Form;
        public AuditPassEvent ( IEmpService emp, IFormInterService form )
        {
            this._Form = form;
            this._Emp = emp;
        }
        public AfootAuditLogItem ItemAudit ( AuditFlowBody flow, FlowAuditLogState log, AuditRes result )
        {
            AfootAuditLogItem item = log.LogItem.Find(a => a.Id == result.ItemId);
            item.CheckAuditItem(result);
            item.AuditState = FlowAuditItemStatus.审核通过;
            item.AuditOpinion = result.Opinion;
            item.SignFileId = result.SignFileId;
            item.SubFlowState = this._LoadNextStep(flow, item, log, result.NextNode);
            FlowNode node = flow.Nodes[item.NodeId];
            this._SyncMultipleState(node, log, item);
            this._CheckWhileNode(node, log, item);
            return item;
        }
        private void _CheckWhileNode ( FlowNode node, FlowAuditLogState log, AfootAuditLogItem item )
        {
            if ( node.NodeType == FlowNodeType.循环处理节点 && item.NextDeptId.HasValue )
            {
                log.SetNodeState(node.Id, FlowNodeAuditStatus.审核进行中, item.Id);
            }
        }
        private void _SyncMultipleState ( FlowNode node, FlowAuditLogState log, AfootAuditLogItem item )
        {
            if ( node.AuditType != FlowAuditType.多人会审 )
            {
                return;
            }
            if ( this._MultipleIsPass(node, item, log) )
            {
                log.SetNodeState(node.Id, FlowNodeAuditStatus.审核通过, item.Id);
                log.LogItem.ForEach(a =>
                {
                    if ( a.NodeId == node.Id && a.Status == FlowAuditItemStatus.审核进行中 )
                    {
                        a.Status = FlowAuditItemStatus.已作废;
                        a.OptItemId = item.Id;
                    }
                });
            }
            else
            {
                log.SetNodeState(node.Id, FlowNodeAuditStatus.审核进行中, item.Id);
            }
        }
        private bool _MultipleIsPass ( FlowNode node, AfootAuditLogItem item, FlowAuditLogState log )
        {
            if ( node.MinAuditPass.HasValue == false && log.LogItem.IsExists(c => c.NodeId == node.Id && c.AuditState == FlowAuditItemStatus.审核进行中) )
            {
                return false;
            }
            List<AfootAuditLogItem> states = log.LogItem.FindAll(a => a.NodeId == item.NodeId && a.RootBatchNo == item.RootBatchNo);
            states = states.Filters(item);
            if ( states.Count == 1 )
            {
                return true;
            }
            int num = states.Count(c => c.Status == FlowAuditItemStatus.审核通过);
            if ( num == states.Count )
            {
                return true;
            }
            else if ( node.MinAuditPass.HasValue == false )
            {
                return false;
            }
            else if ( node.IsRatio == false && node.MinAuditPass.Value > states.Count )
            {
                return num == states.Count;
            }
            else if ( node.IsRatio )
            {
                num = num * 100 / states.Count;
            }
            return num >= node.MinAuditPass.Value;
        }
        private long[] _CheckData ( AuditFlowBody body, ChioseAuditNode[] nexts, out bool isSubFlow )
        {
            bool isSub = false;
            List<long> empId = new List<long>();
            nexts.ForEach(c =>
            {
                if ( !body.Nodes.TryGetValue(c.NodeId, out FlowNode node) )
                {
                    throw new ErrorException("flow.audit.node.not.find");
                }
                else if ( node.NodeType == FlowNodeType.结束节点 )
                {
                    return;
                }
                else if ( c.EmpId.IsNull() )
                {
                    throw new ErrorException("flow.audit.emp.null");
                }
                else if ( node.AuditType == FlowAuditType.独立审批 && c.EmpId.Length > 1 )
                {
                    throw new ErrorException("flow.audit.emp.num.error");
                }
                if ( node.NodeType == FlowNodeType.子流程 )
                {
                    isSub = true;
                }
                empId.AddRange(c.EmpId);
            });
            isSubFlow = isSub;
            return empId.ToArray();
        }

        private class _ItemKey
        {
            public long rootNodeId;
            public FlowNodeType nodeType;
        }
        private FlowSubAuditStatus _LoadNextStep ( AuditFlowBody body, AfootAuditLogItem item, FlowAuditLogState log, ChioseAuditNode[] nexts )
        {
            if ( nexts.IsNull() )
            {
                return FlowSubAuditStatus.审核通过;
            }
            FlowNode form = body.Nodes[item.NodeId];
            List<_ItemKey> items = new List<_ItemKey>();
            long[] empId = this._CheckData(body, nexts, out bool isSubFlow);
            FlowAuditItemStatus itemStatus = FlowAuditItemStatus.审核进行中;
            FlowSubAuditStatus subStatus = FlowSubAuditStatus.审核通过;
            if ( isSubFlow && form.OutCondition != FlowOutCondition.无 && form.OutIsWaitPass )
            {
                itemStatus = FlowAuditItemStatus.待开始;
                subStatus = FlowSubAuditStatus.审核进行中;
            }
            EmpBase[] emps = this._Emp.GetBase(empId);
            FlowItemMarkState mark = FlowItemMarkState.普通;
            long? optId = null;
            if ( item.MarkState == FlowItemMarkState.向前加签 )
            {
                mark = FlowItemMarkState.回签;
                optId = item.Id;
            }
            nexts.ForEach(c =>
            {
                FlowNode node = body.Nodes[c.NodeId];
                this._ToVoidNoAudit(body, log, node, form, item.Id);
                if ( c.ItemId.HasValue )
                {
                    mark = FlowItemMarkState.回源;
                    optId = c.ItemId.Value;
                }
                if ( node.NodeType == FlowNodeType.结束节点 )
                {
                    if ( items.IsExists(a => a.rootNodeId == node.RootNodeId) )
                    {
                        throw new ErrorException("flow.audit.node.config.error");
                    }
                    items.Add(new _ItemKey
                    {
                        rootNodeId = node.RootNodeId,
                        nodeType = node.NodeType,
                    });
                    log.LogItem.Add(new AfootAuditLogItem
                    {
                        NodeType = node.NodeType,
                        EmpByDeptId = item.EmpByDeptId,
                        EmpId = item.EmpId,
                        Status = FlowAuditItemStatus.审核通过,
                        AuditState = FlowAuditItemStatus.审核通过,
                        SubFlowState = FlowSubAuditStatus.审核通过,
                        EmpByUnitId = item.EmpByUnitId,
                        RootNodeId = node.RootNodeId,
                        CompanyId = item.CompanyId,
                        RootBatchNo = item.RootBatchNo,
                        NodeId = node.Id,
                        PrevNodeId = item.NodeId,
                        PrevBackNo = item.BatchNo,
                        TimeOut = null
                    });
                }
                else if ( items.IsExists(a => a.rootNodeId == node.RootNodeId && a.nodeType == FlowNodeType.结束节点) )
                {
                    throw new ErrorException("flow.audit.node.config.error");
                }
                else if ( node.AuditType == FlowAuditType.独立审批 )
                {
                    items.Add(new _ItemKey
                    {
                        rootNodeId = node.RootNodeId,
                        nodeType = node.NodeType,
                    });
                    long empid = c.EmpId[0];
                    EmpBase emp = emps.Find(a => a.EmpId == empid);
                    AfootAuditLogItem add = new AfootAuditLogItem
                    {
                        NodeType = node.NodeType,
                        EmpByDeptId = emp.DeptId,
                        EmpId = empid,
                        EmpByUnitId = emp.UnitId,
                        RootNodeId = node.RootNodeId,
                        NodeId = node.Id,
                        PrevNodeId = item.NodeId,
                        NextDeptId = c.NextDeptId,
                        CompanyId = emp.CompanyId,
                        PrevBackNo = item.BatchNo,
                        MarkState = mark,
                        OptItemId = optId,
                        TimeOut = node.LimitTime.HasValue ? DateTime.Now.AddMinutes(node.LimitTime.Value) : null,
                        CopyId = c.CopyEmpId
                    };
                    if ( node.NodeType == FlowNodeType.子流程 || itemStatus == FlowAuditItemStatus.审核进行中 )
                    {
                        if ( node.StartMode == FlowNodeStartMode.设定时间 )
                        {
                            add.StartTime = DateTime.Now.Date.AddMinutes(node.DelayTime.Value);
                            add.AuditState = FlowAuditItemStatus.待开始;
                        }
                        else if ( node.StartMode == FlowNodeStartMode.读取表单字段 )
                        {
                            add.StartTime = this._GetFormStartTime(node, log);
                            if ( add.StartTime.HasValue )
                            {
                                add.AuditState = FlowAuditItemStatus.待开始;
                            }
                        }
                    }
                    if ( node.NodeType != FlowNodeType.子流程 )
                    {
                        if ( itemStatus == FlowAuditItemStatus.待开始 )
                        {
                            add.AuditState = itemStatus;
                        }
                        add.RootBatchNo = item.RootBatchNo;
                    }
                    if ( node.NodeType == FlowNodeType.循环处理节点 && item.NodeId == node.Id )
                    {
                        add.PrtBatchNo = item.PrtBatchNo.GetValueOrDefault(item.BatchNo);
                    }
                    log.LogItem.Add(add);
                }
                else
                {
                    items.Add(new _ItemKey
                    {
                        rootNodeId = node.RootNodeId,
                        nodeType = node.NodeType,
                    });
                    DateTime? timeOut = null;
                    if ( node.LimitTime.HasValue )
                    {
                        timeOut = DateTime.Now.AddMinutes(node.LimitTime.Value);
                    }
                    long? rootId = null;
                    FlowAuditItemStatus status = FlowAuditItemStatus.审核进行中;
                    if ( node.NodeType != FlowNodeType.子流程 )
                    {
                        status = itemStatus;
                        rootId = item.RootBatchNo;
                    }
                    DateTime? startTime = null;
                    if ( node.StartMode == FlowNodeStartMode.设定时间 )
                    {
                        status = FlowAuditItemStatus.待开始;
                        startTime = DateTime.Now.Date.AddMinutes(node.DelayTime.Value);
                    }
                    else if ( node.StartMode == FlowNodeStartMode.读取表单字段 )
                    {
                        startTime = this._GetFormStartTime(node, log);
                        if ( startTime.HasValue )
                        {
                            status = FlowAuditItemStatus.待开始;
                        }
                    }
                    c.EmpId.ForEach(e =>
                    {
                        EmpBase emp = emps.Find(a => a.EmpId == e);
                        log.LogItem.Add(new AfootAuditLogItem
                        {
                            NodeType = node.NodeType,
                            EmpByDeptId = emp.DeptId,
                            EmpId = emp.EmpId,
                            CompanyId = emp.CompanyId,
                            AuditState = status,
                            EmpByUnitId = emp.UnitId,
                            NextDeptId = c.NextDeptId,
                            RootBatchNo = rootId,
                            RootNodeId = node.RootNodeId,
                            NodeId = node.Id,
                            MarkState = mark,
                            OptItemId = optId,
                            PrevNodeId = item.NodeId,
                            PrevBackNo = item.BatchNo,
                            TimeOut = timeOut,
                            StartTime = startTime
                        });
                    });
                }
            });
            return subStatus;
        }
        private DateTime? _GetFormStartTime ( FlowNode node, FlowAuditLogState log )
        {
            FormVal val = this._Form.GetFormValue(new FormValGetArg
            {
                ColumnId = node.StartColId.Value,
                FormId = node.StartFormId.Value,
                LinkPK = log.LinkPk,
                LinkType = log.LinkType
            });
            if ( val == null || ( val.DataType != FormRecordDataType.Date && val.DataType != FormRecordDataType.DateTime ) )
            {
                return null;
            }
            return val.LongVal.Value.ToDateTime();
        }
        /// <summary>
        /// 作废其它分支中未审批的节点
        /// </summary>
        /// <param name="log"></param>
        /// <param name="to"></param>
        /// <param name="form"></param>
        private void _ToVoidNoAudit ( AuditFlowBody body, FlowAuditLogState log, FlowNode to, FlowNode form, long optItemId )
        {
            if ( to.PrevNodeId.Length == 1 )
            {
                return;
            }
            List<long> parentId = new List<long>(to.ParentId);
            _ = parentId.Remove(form.Id);
            _ = parentId.RemoveAll(a => form.ParentId.Contains(a));
            if ( parentId.Count > 0 )
            {
                parentId.ForEach(c =>
                {
                    log.SetNodeState(c, FlowNodeAuditStatus.待开始, optItemId, FlowNodeAuditStatus.审核进行中);
                });
                log.LogItem.ForEach(c =>
                {
                    if ( c.Status == FlowAuditItemStatus.审核进行中 )
                    {
                        if ( c.RootNodeId == form.RootNodeId && parentId.Contains(c.NodeId) )
                        {
                            c.Status = FlowAuditItemStatus.已作废;
                            c.OptItemId = optItemId;
                        }
                        else
                        {
                            FlowNode node = body.Nodes[c.NodeId];
                            if ( node.ParentId.IsExists(a => parentId.Contains(a)) )
                            {
                                c.Status = FlowAuditItemStatus.已作废;
                                c.OptItemId = optItemId;
                            }
                        }
                    }
                });
            }
        }
    }
}
